package org.micode.common.domain.base;

import org.micode.common.domain.base.entity.BaseDelUpdEntity;
import org.micode.common.domain.base.entity.BaseNormalEntity;
import org.micode.common.domain.base.entity.BaseUpdEntity;
import org.micode.common.utils.BeanExtUtils;
import org.micode.common.utils.CharUtils;
import org.micode.common.utils.DateUtils;
import org.micode.common.utils.StringExtUtils;
import org.micode.common.domain.Page;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Data
@Slf4j
public abstract class BaseQuery<ET extends BaseEntity> {

    /**
     * 查询条件(精确)
     */
    private ET example;

    /**
     * 分页信息
     */
    private Page page;

    public BaseQuery() {
        initForNewQuery();
    }

    protected abstract void initForNewQuery();

    public List<String> getExtConditions() {
        return null;
    }

    public List<String> getSelfConditions(Object object) {
        return getSelfConditions(object, null);
    }

    public List<String> getSelfConditions(Object object, Map<String, String> specMap) {
        Map<String, Object> map = getSelfConditionMap(object);

        List<String> ret = new ArrayList<>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (null != value) {
                if (!(value instanceof Page) &&
                        !(value instanceof BaseEntity)) {
                    if (null != specMap && specMap.keySet().contains(key) &&
                        !StringExtUtils.isAnyEmpty(specMap.get(key))) {
                        String calcFlag = specMap.get(key).trim().toLowerCase();
                        if ("in".equals(calcFlag)) {
                            ret.add(String.format("%s in ('%s')", key, value.toString()));
                        } else if ("like".equals(calcFlag)) {
                            ret.add(String.format("%s like '%%%s%%'", key, value.toString()));
                        } else {
                            ret.add(String.format("%s %s '%s'", key, specMap.get(key), value.toString()));
                        }
                    } else {
                        ret.add(String.format("%s = '%s'", key, value.toString()));
                    }
                }
            }
        }

        log.debug("查询条件Map：{}", StringExtUtils.mapToString(map));
        log.debug("查询条件List：{}", StringExtUtils.listToString(ret));

        return ret.size() <= 0 ? null : ret;
    }

    public String concatDateConditionStr(List<String> condList,
                                         String fieldName, String compType, Date dateValue) {
        if (null != dateValue && !StringExtUtils.isAnyEmpty(fieldName) &&
                !StringExtUtils.isAnyEmpty(compType)) {
            String dateZeroHour = DateUtils.date2Str(dateValue, "yyyy-MM-dd") + " 00:00:00";
            condList.add(fieldName + compType + "'" + dateZeroHour + "'");
        }
        return null;
    }

    public Map<String, Object> getSelfConditionMap(Object object) {
        // DO实体类型
        Class<?> cls = object.getClass();
        return readClassConditionMap(cls, object);
    }

    public Map<String, Object> getConditionMap(Object object) {
        // DO实体类型
        Class<?> cls = readEntityClass(object.getClass());
        return readClassConditionMap(cls, object);
    }

    public Map<String, Object> getConditionMap() {
        return getConditionMap(example);
    }

    private Map<String, Object> readClassConditionMap(Class<?> cls, Object object) {
        Map<String, Object> ret = new HashMap<>();
        String[] fields = BeanExtUtils.getSelfAllFiledName(cls);
        if (fields.length <= 0) {
            return null;
        }

        for (String field : fields) {
            log.debug("Field: {}", field);
            try {
                Object fieldVal = BeanExtUtils.getFieldValueByName(object, field);
                if (fieldVal != null) {
                    if (fieldVal instanceof String) {
                        if (StringUtils.isNotBlank((String) fieldVal)) {
                            ret.put(getFieldName(field), fieldVal);
                        }
                    } else {
                        ret.put(getFieldName(field), fieldVal);
                    }
                }
            } catch (Exception e) {
                log.error("Fail", e);
            }
        }

        return ret;
    }

    protected Class<?> readEntityClass(Class<?> cls) {
        if (BaseNormalEntity.class.equals(cls.getSuperclass()) ||
                BaseDelUpdEntity.class.equals(cls.getSuperclass()) ||
                BaseUpdEntity.class.equals(cls.getSuperclass()) ||
                BaseEntity.class.equals(cls.getSuperclass()) ||
                Object.class.equals(cls.getSuperclass())) {
            return cls;
        } else {
            return readEntityClass(cls.getSuperclass());
        }
    };

    protected String getFieldName(String fieldName) {
        char[] ch = fieldName.toCharArray();

        ch[0] = CharUtils.toLowerChar(ch[0]);

        StringBuilder sb = new StringBuilder();

        for (char c : ch) {
            if (CharUtils.isUpperChar(c)) {
                sb.append("_");
            }
            sb.append(c);
        }

        return sb.toString().toLowerCase();
    }

}
